<template>
  <menuComp :menu="menu"></menuComp>
</template>
<script setup lang="ts">
import {
  deviceExcel,
  exportDevice,
  exportPoints,
  getDeviceAnnotation,
  getTunnelPoint,
  importDevice,
  importPoints,
  saveModel
} from '@renderer/api'
import { tunnelExcel } from '@renderer/api'
import menuComp from '../components/menuComp.vue'
import { ElLoading, ElMessage } from 'element-plus'
import { useViewportStore } from '@renderer/stores/viewport'
import { storeToRefs } from 'pinia'
import emiter from '@renderer/utils/mitt'
import { nextTick } from 'vue'
import { useHistory } from '@renderer/utils/useHistory'
import { GLTFExporter, GLTFLoader, TGALoader } from 'three/examples/jsm/Addons'
import { LoadingManager } from 'three'
import { MeshoptDecoder } from 'three/examples/jsm/libs/meshopt_decoder.module'
import { useAddTools } from '@renderer/utils/useAddTools'

const viewportStore = useViewportStore()
const { publicGroup } = storeToRefs(viewportStore)
// 保存
async function handleSave() {
  const data = publicGroup.value?.toJSON()
  data.object.children = data.object.children?.filter((obj) => obj.name !== 'editor')
  await saveModel(data)
  ElMessage.success('保存成功')
}
// 下载模版
function handleDownloadWireDataTpl() {
  tunnelExcel()
}
// 导入导线数据
const { commitHistory } = useHistory()
const { loadWireToScene, editEquipment } = useAddTools()
function handleImportWireData() {
  const fileInput = document.createElement('input')
  fileInput.multiple = true
  fileInput.accept = '.xls, .xlsx'
  fileInput.type = 'file'
  fileInput.addEventListener('change', async function () {
    const file = fileInput.files[0]
    const loading = ElLoading.service({
      lock: true,
      text: 'Loading',
      background: 'rgba(0, 0, 0, 0.7)'
    })
    // 导入导线数据
    try {
      await importPoints(file)
      // 获取导线数据
      const { data } = await getTunnelPoint()
      if (data) {
        // 生成巷道
        loadWireToScene(data)
        const modelData = publicGroup.value?.children
        // 保存巷道数据
        setTimeout(() => {
          saveModel(JSON.parse(JSON.stringify(modelData)))
        }, 1000)
      }
    } finally {
      loading.close()
    }
  })
  fileInput.click()
}
// 导出导线数据
function handleExportWireData() {
  // TODO
  exportPoints()
}
// 导入模型
function handleImportModel() {
  const fileInput = document.createElement('input')
  fileInput.multiple = true
  fileInput.type = 'file'
  fileInput.accept = '.glb, .gltf'
  fileInput.addEventListener('change', function () {
    if (fileInput.files) {
      loadFiles(fileInput.files) //获取上传的文件
    }
  })
  fileInput.click()

  function loadFiles(files: FileList) {
    if (files.length > 0) {
      const filesMap = createFilesMap(files)
      const manager = new LoadingManager()
      manager.setURLModifier(function (url) {
        url = url.replace(/^(\.?\/)/, '') // 去掉 './'
        const file = filesMap[url]
        if (file) {
          return URL.createObjectURL(file)
        }
        return url
      })
      manager.addHandler(/\.tga$/i, new TGALoader())
      for (let i = 0; i < files.length; i++) {
        loadFile(files[i], manager)
      }
    }
  }

  function createFilesMap(files: FileList) {
    const map: any = {}
    for (let i = 0; i < files.length; i++) {
      const file = files[i]
      map[file.name] = file
    }
    return map
  }

  function loadFile(file: File, manager: LoadingManager) {
    const filename = file.name!
    const extension = filename.split('.').pop().toLowerCase()
    const reader = new FileReader()
    reader.addEventListener('progress', function (event) {
      const size =
        '(' +
        new Intl.NumberFormat('en-us', { useGrouping: true }).format(
          Math.floor(event.total / 1000)
        ) +
        ' KB)'
      const progress = Math.floor((event.loaded / event.total) * 100) + '%'
      console.log('Loading', filename, size, progress)
    })

    if (['glb', 'gltf'].includes(extension)) {
      reader.addEventListener(
        'load',
        async function (event: any) {
          const contents = event.target.result
          const loader = await createGLTFLoader(extension === 'glb' ? undefined : manager)
          loader.parse(contents, '', function (result) {
            const scene = result.scene
            scene.animations.push(...result.animations)
            publicGroup.value?.add(scene)

            nextTick(() => {
              emiter.emit('viewChange')
              commitHistory(`添加物体${scene.name}`, 'add')
            })
          })
        },
        false
      )
      reader.readAsArrayBuffer(file)
    } else {
      console.error('暂不支持 (' + extension + ')文件类型')
    }
  }

  async function createGLTFLoader(manager: LoadingManager | undefined) {
    const loader = new GLTFLoader(manager)
    loader.setMeshoptDecoder(MeshoptDecoder) // 解压
    return loader
  }
}
// 导出模型
function handleExportModel(type: 'glb' | 'gltf') {
  const model = publicGroup.value?.children
  const name = `3deditor-${Date.now()}`

  const animations = getAnimations(publicGroup.value)

  const optimizedAnimations = []

  for (const animation of animations) {
    optimizedAnimations.push(animation.clone().optimize())
  }

  const exporter = new GLTFExporter()
  exporter.parse(
    model,
    function (result) {
      if (type === 'glb') {
        saveArrayBuffer(result, name + '.glb')
      } else if (type === 'gltf') {
        saveString(JSON.stringify(result, null, 2), name + '.gltf')
      }
    },
    () => {},
    { binary: type === 'glb', animations: optimizedAnimations }
  )

  function getAnimations(scene: any) {
    const animations: any = []
    scene.traverse(function (object: any) {
      animations.push(...object.animations)
    })
    return animations
  }
  function saveString(text: string, filename: string) {
    save(new Blob([text], { type: 'text/plain' }), filename)
  }
  function saveArrayBuffer(buffer: any, filename: string) {
    save(new Blob([buffer], { type: 'application/octet-stream' }), filename)
  }
  function save(blob: Blob, filename: string) {
    const link = document.createElement('a')
    if (link.href) {
      URL.revokeObjectURL(link.href)
    }
    link.href = URL.createObjectURL(blob)
    link.download = filename || 'data.json'
    link.dispatchEvent(new MouseEvent('click'))
  }
}

// 下载设备模版
function handleDownloadDeviceTpl() {
  deviceExcel()
}
// 导入设备
function handleImportDevice() {
  const fileInput = document.createElement('input')
  fileInput.multiple = true
  fileInput.accept = '.xls, .xlsx'
  fileInput.type = 'file'
  fileInput.addEventListener('change', async function () {
    const file = fileInput.files[0]
    const loading = ElLoading.service({
      lock: true,
      text: 'Loading',
      background: 'rgba(0, 0, 0, 0.7)'
    })
    // 导入导线数据
    try {
      await importDevice(file)
      // 获取设备数据
      const { data } = await getDeviceAnnotation()
      if (data) {
        // 生成设备
        data.forEach((item) => {
          editEquipment({
            ...item,
            coordinates: {
              x: item.x,
              y: item.h,
              z: item.y
            }
          })
        })
      }
    } finally {
      loading.close()
    }
  })
  fileInput.click()
}
// 导出设备
function handleExportDevice() {
  exportDevice()
}

const menu = {
  label: '文件',
  children: [
    { label: '保存', shortcutKey: 'Ctrl+S', click: handleSave },
    {
      label: '导线',
      children: [
        { label: '下载模版', shortcutKey: '', click: handleDownloadWireDataTpl },
        { label: '导入', shortcutKey: '', click: handleImportWireData },
        { label: '导出', shortcutKey: '', click: handleExportWireData }
      ]
    },
    {
      label: '设备',
      children: [
        { label: '下载模版', shortcutKey: '', click: handleDownloadDeviceTpl },
        { label: '导入', shortcutKey: '', click: handleImportDevice },
        { label: '导出', shortcutKey: '', click: handleExportDevice }
      ]
    },
    { label: '导入模型', shortcutKey: '', click: handleImportModel },
    {
      label: '导出',
      shortcutKey: '',
      children: [
        { label: 'GLB', click: () => handleExportModel('glb') },
        { label: 'GLTF', click: () => handleExportModel('gltf') }
      ]
    }
  ]
}
</script>
<style lang="scss" scoped></style>
